<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .contanier{
      text-align: center;
    }
    #content{
      width: 640px;
      margin: auto;
      position: relative;
    }
    #canvas{
      position: absolute;
    }
  </style>
</head>
<body>
  <div class="contanier">
    <h1>弹幕来了！！！</h1>
    <div id="content">
      <canvas id="canvas"></canvas>
      <video id="video" src="./video/3、全局CSS样式-排版.mp4" width="640" height="380" controls></video>
      </div>
      <input id="text" type="text">
      <button id="add">添加弹幕</button>
      <input id="color" type="color">
      <input id="range" type="range" max="40" min="20">
  </div>
  <script>
    let data =[
      {value:'我在看视频1',speed:2,time:0,color:'#ffffff',fontSize:20},
      {value:'我在看视频2222',speed:2,time:1,color:'bule',fontSize:20},
      {value:'我在看视频3333',speed:2,time:5,color:'red',fontSize:20},
      {value:'我在看视频56fgffff',speed:2,time:6,color:'red',fontSize:20}
    ]
    let dom = document.querySelector.bind(document)
    let canvas = dom('#canvas')
    let video = dom('#video')
    
    class Barrage{
      constructor(obj,ctx){
      this.value=obj.value
      this.time =obj.time
      this.obj =obj
      this.ctx=ctx
      }
      init(){
        this.opacity =this.obj.opacity || this.ctx.opacity
        this.color=this.obj.color|| this.ctx.color
        this.fontSize =this.obj.fontSize || this.ctx.fontSize
        this.speed=this.obj.speed || this.ctx.speed
        // 求自己的宽度，目的是用来校验当前还需要绘制
        let span =document.createElement('span')
        span.innerText =this.value
        span.style.fontSize=this.fontSize+'px'
        span.style.position = 'absolute'
        document.body.appendChild(span)
        this.width = span.clientWidth
        document.body.removeChild(span)

        // 弹幕的出现为止
        this.x =this.ctx.canvas.width
        this.y =this.ctx.canvas.height * Math.random()
        if(this.y <this.fontSize){
          this.y=this.fontSize
        }
        if(this.y > this.ctx.canvas.height-this.fontSize){
          this.y =this.ctx.canvas.height - this.fontSize
        }

      }
      render(){
        this.ctx.context.font = this.fontSize+'px'
        this.ctx.context.fillStyle=this.color
        this.ctx.context.fillText(this.value,this.x,this.y)
      }
    }


    class BulletChat{
      constructor(canvas,video,option={}){
        if(!canvas || !video){
          return 
        }
        this.canvas=canvas
        this.video=video
        // 默认选项
        let defaultOption = {
          fontSize:20,
          color:'gold',
          speed:2,
          opacity:0.3,
          data:[]
        }
        // 创建画布
        this.context = canvas.getContext('2d')
        this.canvas.width = video.clientWidth
        this.canvas.height = video.clientHeight
        // 对象合并，将属性全部挂在在实例上
        Object.assign(this,defaultOption,option)
        this.isPaused = true 
        // 存放弹幕
        this.barrages=this.data.map(obj=>new Barrage(obj,this))
        // 渲染弹幕
        this.render()
      }
      renderBarrage(){ // 将数组中的弹幕一一取出，判断时间和视频时间是否符合，符合就执行渲染
        let time= this.video.currentTime // 视频播放的当前时间
        this.barrages.forEach(barrage=>{
          if( !barrage.flag && time >= barrage.time){
            // 先初始化后进行绘制
            // 没有初始化先初始化
            if(!barrage.isinited){
              barrage.init()
              barrage.isinited=true
            }
            barrage.x -= barrage.speed
            barrage.render() // 渲染自己
            if(barrage.x < barrage.width*-1){
             barrage.flag =true  // 停止渲染的标志
            }
          }
        })
      }
      add(obj){
      this.barrages.push(new Barrage(obj,this))
      }
      reset(){
        this.context.clearRect(0,0,this.canvas.width,this.canvas.height)
        let time =this.video.currentTime
        this.barrages.forEach(barrage=>{
         barrage.flag =false
         if(time<=barrage.time){
           barrage.isinited=false // 重新初始化
         }else{
          barrage.flag=true // 其他弹幕不再渲染
         }
        })
      }
      render(){
        // 第一次清空操作，执行渲染弹幕，如果没有暂停继续渲染
        this.context.clearRect(0,0,this.canvas.width,this.canvas.height)
        this.renderBarrage() // 渲染弹幕
        if(this.isPaused===false){
          // 递归渲染
          requestAnimationFrame(this.render.bind(this))
        }
      }
    }

    let bulletChat 
    let scoket =new WebSocket('ws://192.168.0.102:3000') // 链接服务端
    scoket.onopen=function(){
      scoket.onmessage=function(e){ // 监听数据的到来

      let data=JSON.parse(e.data) // 服务端发来的消息
      if(data.type === 'init'){ // 数据初始化
        bulletChat= new BulletChat(canvas,video,{data:data.data})
      }
        if(data.type === 'add'){
        bulletChat.add(data.data)
       }
      }
    }
    video.addEventListener('play',function(){
      bulletChat.isPaused = false
      bulletChat.render()
    })

    video.addEventListener('pause',function(){
      bulletChat.isPaused = true
    })

    dom('#add').addEventListener('click',function(){
       let value =dom('#text').value
       let time = video.currentTime
       let color = dom('#color').value
       let fontSize = dom('#range').value
       let obj ={
        value,
        time,
        color,
        fontSize
      }
      scoket.send(JSON.stringify(obj)) // 往服务端添加数据
      // bulletChat.add(obj) // 添加弹幕
      // dom('#text').value=''
    })
     // 视频拖回去执行
    video.addEventListener('seeked',function(){
      bulletChat.reset()
    })

  </script>
</body>
</html>